﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace PokerAssistant.Models
{
    public class Tõenäosus
    {
        public Diiler Diiler { get; set; }
        public List<Kaart> KaardidLaual { get; private set; }
        public List<List<Kaart>> KaardiKombinatsioonid { get; set; }
        public List<List<Kaart>> KolmikuteKombinatsioonid { get; set; }
        public int Mitu { get; set; }
        public int Mitmest { get; set; }

        public Tõenäosus()
        {
            Diiler = new Diiler(true);

            KaardidLaual = new List<Kaart>();
        }

        public void PaneLaualeKaardid(int mitu)
        {
            KaardidLaual = Diiler.Kaardid.GetRange(0, mitu);
        }

        public void TeeKaardiKombinatsioonid(List<Kaart> kaardid, int mitmeKaupa)
        {
            KaardiKombinatsioonid = AnnaKõikKaartideKombinatsioonid(kaardid, mitmeKaupa);
        }

        public static List<List<Kaart>> AnnaMitmikuteKombinatsioonid(int mitmik, List<List<Kaart>> kombinatsioonid)
        {
            return kombinatsioonid.Where(komb => 
                komb.Count(k => k.Mast == Mast.RISTI) == mitmik || 
                komb.Count(k => k.Mast == Mast.POTI) == mitmik ||
                komb.Count(k => k.Mast == Mast.ÄRTU) == mitmik ||
                komb.Count(k => k.Mast == Mast.RUUTU) == mitmik).ToList();
        }

        public static List<List<Kaart>> AnnaPaarideKombinatsioonid(List<List<Kaart>> kombinatsioonid)
        {
            return AnnaMitmikuteKombinatsioonid(2, kombinatsioonid);
        }

        public static List<List<Kaart>> AnnaKolmikuteKombinatsioonid(List<List<Kaart>> kombinatsioonid)
        {
            return AnnaMitmikuteKombinatsioonid(3, kombinatsioonid);
        }

        public static int ArvutaKombinatsioonid(int mitmeKaupa, int mitmest)
        {
            return mitmeKaupa <= mitmest ? Faktoriaal(mitmest) / (Faktoriaal(mitmeKaupa) * Faktoriaal(mitmest - mitmeKaupa)) : 0;
        }

        public static int Faktoriaal(int n)
        {
            return n <= 0 ? 1 : n * Faktoriaal(n - 1);
        }

        public static List<List<Kaart>> AnnaKõikKaartideKombinatsioonid(List<Kaart> kaardid, int mitmeKaupa)
        {
            if (mitmeKaupa > kaardid.Count)
                return new List<List<Kaart>>();

            var kombinatsioonid = AnnaKombinatsioonid(mitmeKaupa, kaardid.Count);

            var kaartideKombinatsioonid = new List<List<Kaart>>();

            foreach (var kombinatsioon in kombinatsioonid)
            {
                for (var i = 0; i < kombinatsioon.Count; i++)
                {
                    kaardid[i].Valitud = kombinatsioon[i] == 1;
                }
                kaartideKombinatsioonid.Add(Koopia(kaardid.Where(k => k.Valitud).ToList()));
            }

            return kaartideKombinatsioonid;
        }

        public static List<List<int>> AnnaKombinatsioonid(int mitmeKaupa, int mitmest)
        {
            int valitudLõpus;
            var kombinatsioonid = new List<List<int>>();

            var kombinatsioon = new List<int>();
            for (var i = 0; i < mitmeKaupa; i++) 
                kombinatsioon.Add(1);
            for (var i = 0; i < mitmest - mitmeKaupa; i++)
                kombinatsioon.Add(0);

            kombinatsioonid.Add(Koopia(kombinatsioon));

            do
            {
                int valimataLõpus = 0;
                for (int i = mitmest - 1; i > 0 && kombinatsioon[i] == 0; i--, valimataLõpus++) ;

                for (int i = mitmest - valimataLõpus - 1; valimataLõpus > 0; valimataLõpus--)
                {
                    kombinatsioon.RemoveAt(mitmest - 1);
                    kombinatsioon.Insert(i, 0); // liiguta viimast valitud l6ppu
                    kombinatsioonid.Add(Koopia(kombinatsioon));
                }

                valitudLõpus = 0;
                for (int i = mitmest - 1; kombinatsioon[i] == 1 && i > 0; i--, valitudLõpus++) ;

                for (int i = mitmest - 1; i > 0 && valitudLõpus > 0; i--)
                {
                    if (kombinatsioon[i - 1] == 1 && kombinatsioon[i] == 0)
                    {
                        for (int k = 0; k < valitudLõpus; k++)
                        {
                            kombinatsioon.Insert(i - 1, 1); // lisa 1 niipalju kui on l6pus
                            kombinatsioon.RemoveAt(mitmest - 1);
                        }
                        kombinatsioon.RemoveAt(mitmest - 1);
                        kombinatsioon.Insert(i - 1, 0); // nihuta paremale
                        break;
                    }
                }

                if (valitudLõpus != mitmeKaupa)  // et l6pus kordust poleks, kui on 1 kaupa n-st
                    kombinatsioonid.Add(Koopia(kombinatsioon)); // v6i n kaupa n-st

            } while (valitudLõpus != mitmeKaupa);

            return kombinatsioonid;
        }

        public static List<T> Koopia<T>(List<T> massiiv)
        {
            var massiivCopy = new List<T>();
            massiivCopy.AddRange(massiiv);
            return massiivCopy;
        }
    }
}